#ifndef _MY_LIST_TCC_
#define _MY_LIST_TCC_

#include <algorithm>

template<typename T>
void my_list<T>::push_front(const T& value) {
	unique_ptr<node<T>> newNode(new node<T>(value));
	lock_guard<mutex> lk(head.m);
	newNode->next = move(head.next);
	head.next = move(newNode);
}

template<typename T>
template<typename Function>
void my_list<T>::for_each(Function f) {
	node<T>* current = &head;
	unique_lock<mutex> lk(head.m);
	while (node<T>* const next = current->next.get()) {
		unique_lock<mutex> nextlk(next->m);
		lk.unlock();
		f(*next->data);
		current = next;
		lk = move(nextlk);
	}
}

template<typename T>
template<typename Predicate>
shared_ptr<T> my_list<T>::find_first_if(Predicate p) {
	node<T>* current = &head;
	unique_lock<mutex> lk(head.m);
	while (node<T>* const next = current->next.get()) {
		unique_lock<mutex> nextlk(next->m);
		lk.unlock();
		if (p(*next->data)) {
			return next->data;
		} else {
			current = next;
			lk = move(nextlk);
		}
	}
	return shared_ptr<T>();
}

template<typename T>
template<typename Predicate>
void my_list<T>::remove_if(Predicate p) {
	node<T>* current = &head;
	unique_lock<mutex> lk(head.m);
	while (node<T>* const next = current->next.get()) {
		unique_lock<mutex> nextlk(next->m);
		if (p(*next->data)) {
			unique_ptr<node<T>> oldNext = move(current->next);
			current->next= move(next->next);
			nextlk.unlock();
		} else {
			lk.unlock();
			current = next;
			lk = move(nextlk);
		}
	}
}

template<typename T>
node<T>* my_list<T>::getHead() {
	return &head;
}

template<typename T>
my_list<T>::~my_list() {
	remove_if([](const T&){return true;});
}

#endif
